package com.hopes.bizz.risk.support;

import cn.hutool.core.collection.CollectionUtil;
import com.hopes.bizz.common.core.util.DateUtils;
import com.hopes.bizz.risk.common.constant.CalendarConstant;
import com.hopes.bizz.risk.common.constant.RiskDicConstant;
import com.hopes.bizz.risk.control.entity.RiskMeasureTaskEntity;
import com.hopes.bizz.risk.control.entity.RiskMeasureTaskRecordEntity;
import com.hopes.bizz.risk.control.service.RiskMeasureTaskService;
import com.hopes.bizz.risk.setting.entity.RiskCalendarEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * @author yumr
 * @ProjectName sd-sfes-web
 * @Description 风险隐患任务生产策略
 * @time 2023/6/16 16:00
 */
@Component
@RequiredArgsConstructor
public class RiskCheckTaskGenSupport {

    private final StringRedisTemplate stringRedisTemplate;

    private final RiskMeasureTaskService riskMeasureTaskService;

    /**
     * 任务生成索引key
     */
    public static final String REDIS_KEY = "RH:RISK_HIDDEN_CHECK_GENERATE_TASK:INDEX:";

    /**
     * 根据字段、值过滤列表数据
     * @param list    列表数据
     * @param mapper  栏位
     * @param value   值
     */
    @SafeVarargs
    public final <T, R> void filterWorkDayType(List<T> list, Function<T, R> mapper, R... value) {
        list.removeIf(next ->
                Objects.isNull(mapper.apply(next))
                        || Arrays.stream(value).noneMatch(item -> item.equals(mapper.apply(next))));
    }


    public boolean checkTaskCycleType(RiskMeasureTaskEntity measureTask, Calendar calendar) {
        if (null == measureTask || null == measureTask.getCheckCycleType() || null == calendar) {
            return false;
        }
        final Date nowDate = calendar.getTime();
        final Integer checkCycle = measureTask.getCheckCycle();
        final Date startCheckDate = measureTask.getStartCheckDate();
        if (null == checkCycle || startCheckDate.after(nowDate)) {
            return false;
        }
        final Date latestCheckDate = measureTask.getLatestCheckDate();
        return null == latestCheckDate || nowDate.after(latestCheckDate);
    }

    public RiskMeasureTaskRecordEntity buildPointHiddenCheckTask(int index, RiskMeasureTaskEntity riskMeasureTask, Date taskStartTime, Date taskDeadlineTime) {
        final RiskMeasureTaskRecordEntity pointHiddenCheckTask = new RiskMeasureTaskRecordEntity();
        pointHiddenCheckTask.setRiskUnitId(riskMeasureTask.getRiskUnitId());
        pointHiddenCheckTask.setRiskEventId(riskMeasureTask.getRiskEventId());
        pointHiddenCheckTask.setRiskControlId(riskMeasureTask.getRiskControlId());
        pointHiddenCheckTask.setRiskCheckConfigId(riskMeasureTask.getId());
        pointHiddenCheckTask.setTaskName(buildTaskName(index, riskMeasureTask, taskStartTime));
        pointHiddenCheckTask.setWorkType(riskMeasureTask.getWorkType());
        pointHiddenCheckTask.setDefendFlag(
                Optional.ofNullable(riskMeasureTask.getWorkType())
                        .map(e -> !e.equals(riskMeasureTask.getWorkType())).orElse(Boolean.FALSE));
        pointHiddenCheckTask.setCheckContent(riskMeasureTask.getCheckContent());
        pointHiddenCheckTask.setResponsibleUserIds(riskMeasureTask.getResponsibleUserIds());
        pointHiddenCheckTask.setTaskStartTime(taskStartTime);
        pointHiddenCheckTask.setTaskDeadlineTime(taskDeadlineTime);
        pointHiddenCheckTask.setTaskStatus(RiskDicConstant.HIDDEN_CHECK_TASK_STATUS_NOT_FINISH);
        return pointHiddenCheckTask;
    }

    private String buildTaskName(int index, RiskMeasureTaskEntity riskMeasureTask, Date taskStartTime) {
        final Optional<RiskMeasureTaskEntity> optional = Optional.ofNullable(riskMeasureTask);
        final String deptIdStr = optional.map(RiskMeasureTaskEntity::getDeptIdStr).orElse("--"); // 责任部门
        final String riskUnitIdStr = optional.map(RiskMeasureTaskEntity::getRiskUnitIdStr).orElse("--");
        final String controlLevelStr = optional.map(RiskMeasureTaskEntity::getControlLevelStr).orElse("--");
        final String taskStartTimeStr = DateUtils.formatDate(taskStartTime, DateUtils.FORMAT_SIMPLE_HOUR);
        return controlLevelStr + "-" + deptIdStr + "-" + riskUnitIdStr + "(" + taskStartTimeStr + generateIndexPrefix(index) + index + ")";
    }

    private String generateIndexPrefix(int index) {
        if (index < 10) {
            return "000";
        } else if (index < 100) {
            return "00";
        } else if (index < 1000) {
            return "0";
        } else {
            return "";
        }
    }

    /**
     * 处理 年\月 周期的任务
     * @param calendar  时间对象
     * @param nowDayStr 当前日期
     * @param taskList  任务
     */
    public List<RiskMeasureTaskRecordEntity> handlerYearAndMonthCycleTask(Calendar instance, int calendar, String nowDayStr, List<RiskMeasureTaskEntity> taskList) {
        final List<RiskMeasureTaskRecordEntity> recordList = new ArrayList<>();
        if (CollectionUtil.isEmpty(taskList)) {
            return recordList;
        }
        final Date nowTime = instance.getTime();
        for (RiskMeasureTaskEntity measureTask : taskList) {
            // 1、计算任务开始时间
            final Date recordStartTime = calculateRecordStartTime(nowTime, nowDayStr, measureTask);
            if (null == recordStartTime) {
                continue;
            }
            int index = Integer.parseInt(Optional.ofNullable(stringRedisTemplate.opsForValue().get(REDIS_KEY + nowDayStr)).orElse("1"));

            // 任务结束时间
            final Date recordEndTime = DateUtils.add(recordStartTime, calendar, measureTask.getCheckCycle());
            recordList.add(buildPointHiddenCheckTask(index, measureTask, recordStartTime, recordEndTime));

            stringRedisTemplate.opsForValue().set(REDIS_KEY + nowDayStr, String.valueOf(index + 1), 86400, TimeUnit.SECONDS);

            // 更新最近一次任务时间
            final RiskMeasureTaskEntity param = new RiskMeasureTaskEntity();
            param.setId(measureTask.getId());
            param.setLatestCheckDate(recordEndTime);
            riskMeasureTaskService.updateById(param);
        }
        return recordList;
    }

    /**
     * 处理 天 周期的任务
     * @param instance    时间对象
     * @param nowDayStr   当前日期
     * @param taskList    任务
     * @return            结果集
     */
    public List<RiskMeasureTaskRecordEntity> handlerDayAndHourCycleTask(Calendar instance, int calendar, String nowDayStr, RiskCalendarEntity sysCalendar, List<RiskMeasureTaskEntity> taskList) {
        final List<RiskMeasureTaskRecordEntity> recordList = new ArrayList<>();
        if (CollectionUtil.isEmpty(taskList)) {
            return recordList;
        }
        // 根据工作日类型筛选数据
        final Integer workDayType = sysCalendar.getDateType().equals(CalendarConstant.WEEKDAY) ? RiskDicConstant.RISK_WORK_DAY_TYPE_1 : RiskDicConstant.RISK_WORK_DAY_TYPE_2;
        this.filterWorkDayType(taskList, RiskMeasureTaskEntity::getWorkDayType, RiskDicConstant.RISK_WORK_DAY_TYPE_0, workDayType);
        if (CollectionUtil.isEmpty(taskList)) {
            return recordList;
        }

        final Date nowTime = instance.getTime();
        for (RiskMeasureTaskEntity measureTask : taskList) {
            // 1、计算任务开始时间
            Date recordStartTime = calculateRecordStartTime(nowTime, nowDayStr, measureTask);
            if (null == recordStartTime) {
                continue;
            }
            // 2、任务开始时间与当前时间比较
            if (calendar == Calendar.HOUR_OF_DAY) {
                while (DateUtils.getIntervalHours(recordStartTime, nowTime) >= 0.75) {
                    recordStartTime = DateUtils.add(recordStartTime, Calendar.HOUR_OF_DAY, 1);
                }
            } else if (calendar == Calendar.DAY_OF_MONTH){
                while (DateUtils.getIntervalDays(recordStartTime, nowTime) >= 1) {
                    recordStartTime = DateUtils.add(recordStartTime, Calendar.DAY_OF_MONTH, 1);
                }
            }
            // 任务结束时间
            Date recordEndTime = DateUtils.add(recordStartTime, calendar, measureTask.getCheckCycle());
            if (calendar == Calendar.HOUR_OF_DAY) {
                final Date workEndTime = DateUtils.parseDate(nowDayStr + " " + measureTask.getWorkEndTime(), DateUtils.FORMAT_SECOND);
                if (recordEndTime.toInstant().getEpochSecond() > workEndTime.toInstant().getEpochSecond()) {
                    continue;
                }
            }

            int index = Integer.parseInt(Optional.ofNullable(stringRedisTemplate.opsForValue().get(REDIS_KEY + nowDayStr)).orElse("1"));

            recordList.add(buildPointHiddenCheckTask(index, measureTask, recordStartTime, recordEndTime));
            stringRedisTemplate.opsForValue().set(REDIS_KEY + nowDayStr, String.valueOf((index + 1)), 86400, TimeUnit.SECONDS);

            // 更新最近一次任务时间
            final RiskMeasureTaskEntity param = new RiskMeasureTaskEntity();
            param.setId(measureTask.getId());
            param.setLatestCheckDate(recordEndTime);
            riskMeasureTaskService.updateById(param);
        }
        return recordList;
    }

    private Date calculateRecordStartTime(Date nowTime, String nowDayStr, RiskMeasureTaskEntity measureTask) {
        if (null == measureTask.getWorkStartTime() || null == measureTask.getWorkEndTime()) {
            return null;
        }
        // 1、工作结束时间 && 工作开始时间 && 任务开始时间
        final Date workEndTime = DateUtils.parseDate(nowDayStr + " " + measureTask.getWorkEndTime(), DateUtils.FORMAT_SECOND);
        final Date workStartTime = DateUtils.parseDate(nowDayStr + " " + measureTask.getWorkStartTime(), DateUtils.FORMAT_SECOND);
        final Date recordStartTime = null == measureTask.getLatestCheckDate() ? measureTask.getStartCheckDate() : measureTask.getLatestCheckDate();
        if (nowTime.before(workStartTime) || nowTime.after(workEndTime) || nowTime.before(recordStartTime)) {
            return null;
        }
        return recordStartTime.before(workStartTime) ? workStartTime : recordStartTime;
    }
}
